import threading
import queue
import time
from typing import Dict, Optional, Any
from datetime import datetime
from collections import deque
import logging
from 统一缓存管理器 import UnifiedCacheManager
from cpu_monitor import CPUMonitor

class AsyncIndicatorCalculator:
    """
    异步指标计算器
    将耗时的指标计算移到后台线程，避免阻塞tick回调
    """
    
    def __init__(self, market_monitor):
        self.market_monitor = market_monitor
        self.calculation_queue = queue.Queue(maxsize=50000)  # 增加队列容量，支持更多并发任务
        
        # 使用统一缓存管理器
        self.cache_manager = UnifiedCacheManager()
        
        # 初始化CPU监控器
        self.cpu_monitor = CPUMonitor()
        
        # 启动多个后台计算线程，提高处理能力
        self.calculation_threads = []
        self.base_thread_count = 500  # 基础线程数量
        self.thread_count = self.base_thread_count
        self.running = False
        
        # 计算频率控制 - 根据指标重要性调整（优化版本）
        self.calculation_intervals = {
            'macd': 1,      # 每1个tick计算一次MACD（重要信号，提高实时性）
            'rsi': 1,       # 每2个tick计算一次RSI（相对稳定，减少间隔）
            'kdj': 1,       # 每2个tick计算一次KDJ（辅助指标，减少间隔）
            'vma': 1,       # 每2个tick计算一次VMA（成交量变化较慢，减少间隔）
            'updown': 1,    # 每1个tick计算涨跌幅（轻量级，实时性要求高）
            'nine_turn': 1, # 每个tick计算九转（轻量级，实时性要求高）
            'nine_turn5m': 1,  # 每个tick计算九转（轻量级，实时性要求高）
            'ma': 1         # 每1个tick计算一次MA（重要指标，实时性要求高）
        }
        
        # 动态频率调整
        self.dynamic_intervals = {}
        self.last_price_change = {}  # 记录价格变化
        self.volatility_threshold = 0.0005  # 价格波动阈值（0.05%），提高灵敏度
        
        # 各指标的tick计数器
        self.tick_counters = {}
        
    def start(self):
        """启动异步计算器"""
        self.running = True
        
        # 启动CPU监控
        self.cpu_monitor.start_monitoring()
        
        # 启动多个计算线程
        self._start_calculation_threads()
        
        # 启动缓存清理线程
        self.cache_manager.start_cleanup_thread()
        
        # 启动动态调整线程
        self._start_dynamic_adjustment_thread()
        
        logging.info(f"异步指标计算器已启动，使用{self.thread_count}个计算线程")
        
    def stop(self):
        """停止异步计算器"""
        self.running = False
        
        # 停止CPU监控
        self.cpu_monitor.stop_monitoring()
        
        logging.info("异步指标计算器已停止")
        
    def _calculation_worker(self):
        """后台计算工作线程"""
        while self.running:
            try:
                # 从队列获取计算任务，超时1秒
                task = self.calculation_queue.get(timeout=1.0)
                if task is None:
                    continue
                    
                self._process_calculation_task(task)
                self.calculation_queue.task_done()
                
            except queue.Empty:
                continue
            except Exception as e:
                logging.error(f"指标计算异常: {e}")
                
    def _process_calculation_task(self, task):
        """处理单个计算任务"""
        try:
            stock_code = task['stock_code']
            indicator_type = task['indicator_type']
            current_price = task['current_price']
            timestamp = task['timestamp']
            
            # 根据指标类型进行计算
            if indicator_type == 'macd':
                result = self._calculate_macd(stock_code, current_price)
            elif indicator_type == 'rsi':
                result = self._calculate_rsi(stock_code)
            # elif indicator_type == 'kdj':
            #     result = self._calculate_kdj(stock_code)
            # elif indicator_type == 'vma':
            #     result = self._calculate_vma(stock_code)
            elif indicator_type == 'updown':
                result = self._calculate_updown(stock_code, current_price)
            elif indicator_type == 'nine_turn':
                result = self._calculate_nine_turn(stock_code, timestamp, current_price)
            elif indicator_type == 'nine_turn5m':
                result = self._calculate_nine_turn5m(stock_code, timestamp, current_price)
            # elif indicator_type == 'ma':
            #     result = self._calculate_ma(stock_code)
            else:
                return
                
            # 使用统一缓存管理器缓存结果
            self.cache_manager.set(stock_code, indicator_type, result)
            
        except Exception as e:
            logging.error(f"处理计算任务异常: {e}")

            
    def _calculate_macd(self, stock_code, current_price):
        """计算MACD指标"""
        try:
            return self.market_monitor.check_macd_signals(stock_code, current_price)
        except Exception as e:
            logging.error(f"MACD计算异常: {e}")
            return None
            
    def _calculate_rsi(self, stock_code):
        """计算RSI指标"""
        try:
            return self.market_monitor.rsi_calculator.get_latest_rsi(stock_code)
        except Exception as e:
            logging.error(f"RSI计算异常: {e}")
            return None
            
    def _calculate_kdj(self, stock_code):
        """计算KDJ指标"""
        try:
            result = self.market_monitor.kdj_calculator.get_latest_kdj(stock_code)
            if result is None:
                logging.warning(f"{stock_code} KDJ计算结果为None，可能数据不足或计算失败")
            return result
        except Exception as e:
            logging.error(f"{stock_code} KDJ计算异常: {e}")
            import traceback
            logging.error(f"{stock_code} KDJ异常堆栈: {traceback.format_exc()}")
            return None
            
    def _calculate_vma(self, stock_code):
        """计算VMA指标"""
        try:
            result = self.market_monitor.vma_calculator.check_volume_surge(stock_code)
            if result is None:
                logging.warning(f"{stock_code} VMA计算结果为None，可能数据不足或计算失败")
            elif not isinstance(result, dict):
                logging.warning(f"{stock_code} VMA计算结果格式异常: {type(result)}")
            return result
        except Exception as e:
            logging.error(f"{stock_code} VMA计算异常: {e}")
            import traceback
            logging.error(f"{stock_code} VMA异常堆栈: {traceback.format_exc()}")
            return None
            
    def _calculate_updown(self, stock_code, current_price):
        """计算涨跌幅指标"""
        try:
            return self.market_monitor.updown_calculator.get_updown(stock_code, current_price)
        except Exception as e:
            logging.error(f"涨跌幅计算异常: {e}")
            return None

    def _calculate_nine_turn(self, stock_code, timestamp, current_price):
        """计算九转指标"""
        try:
            return self.market_monitor.nine_turn.on_tick(stock_code, timestamp, current_price)
        except Exception as e:
            logging.error(f"九转计算异常: {e}")
            return None

    def _calculate_nine_turn5m(self, stock_code, timestamp, current_price):
        """计算5分钟九转指标"""
        try:
            return self.market_monitor.nine_turn5m.on_tick(stock_code, timestamp, current_price)
        except Exception as e:
            logging.error(f"5分钟九转计算异常: {e}")
            return None
            
    def _calculate_ma(self, stock_code):
        """计算MA指标"""
        try:
            result = self.market_monitor.ma_calculator.get_latest_ma(stock_code)
            if result is None:
                logging.warning(f"{stock_code} MA计算结果为None，可能数据不足或计算失败")
            return result
        except Exception as e:
            logging.error(f"{stock_code} MA计算异常: {e}")
            import traceback
            logging.error(f"{stock_code} MA异常堆栈: {traceback.format_exc()}")
            return None
            
    def should_calculate(self, stock_code, indicator_type, current_price=None):
        """判断是否应该计算某个指标（支持动态频率调整）"""
        counter_key = f"{stock_code}_{indicator_type}"
        if counter_key not in self.tick_counters:
            self.tick_counters[counter_key] = 0
            
        self.tick_counters[counter_key] += 1
        
        # 获取基础计算间隔
        base_interval = self.calculation_intervals.get(indicator_type, 1)
        
        # 对于重要指标，根据价格波动动态调整频率
        if indicator_type in ['macd', 'rsi'] and current_price is not None:
            interval = self._get_dynamic_interval(stock_code, indicator_type, current_price, base_interval)
        else:
            interval = base_interval
        
        return self.tick_counters[counter_key] % interval == 0
        
    def _get_dynamic_interval(self, stock_code, indicator_type, current_price, base_interval):
        """根据价格波动动态调整计算间隔"""
        price_key = f"{stock_code}_{indicator_type}"
        
        if price_key not in self.last_price_change:
            self.last_price_change[price_key] = current_price
            return base_interval
            
        last_price = self.last_price_change[price_key]
        price_change_ratio = abs(current_price - last_price) / last_price if last_price > 0 else 0
        
        # 如果价格波动较大，增加计算频率（减少间隔）
        if price_change_ratio > self.volatility_threshold:
            # 价格波动大时，间隔减半
            dynamic_interval = max(1, base_interval // 2)
            self.last_price_change[price_key] = current_price
            return dynamic_interval
        else:
            # 价格稳定时，使用基础间隔
            return base_interval
        
    def submit_calculation(self, stock_code, indicator_type, current_price, timestamp=None):
        """提交计算任务到队列"""
        if not self.should_calculate(stock_code, indicator_type, current_price):
            return
            
        try:
            task = {
                'stock_code': stock_code,
                'indicator_type': indicator_type,
                'current_price': current_price,
                'timestamp': timestamp or time.time()
            }
            
            # 非阻塞方式添加任务
            self.calculation_queue.put_nowait(task)
            
        except queue.Full:
            # 队列满时的处理策略
            queue_size = self.calculation_queue.qsize()
            
            # 如果队列超过80%容量，记录警告
            if queue_size > self.calculation_queue.maxsize * 0.8:
                logging.warning(f"计算队列接近满载 ({queue_size}/{self.calculation_queue.maxsize})，跳过 {stock_code} {indicator_type}")
            
            # 对于重要指标，尝试清理一些旧任务
            if indicator_type in ['macd', 'rsi']:
                self._cleanup_old_tasks(stock_code, indicator_type)
                try:
                    # 再次尝试添加任务
                    self.calculation_queue.put_nowait(task)
                except queue.Full:
                    logging.error(f"重要指标任务无法添加，队列已满: {stock_code} {indicator_type}")
            
    def get_cached_result(self, stock_code, indicator_type):
        """获取缓存的指标结果（带有效性验证）"""
        result = self.cache_manager.get(stock_code, indicator_type)
        
        # 验证缓存结果的有效性
        if result is not None:
            # 对于VMA指标，验证结果格式
            if indicator_type == 'vma':
                if not isinstance(result, dict) or 'is_surge' not in result:
                    logging.warning(f"{stock_code} VMA缓存结果格式无效，清除缓存")
                    self.cache_manager.clear_stock_cache(stock_code)
                    return None
            
            # 对于KDJ指标，验证结果格式
            elif indicator_type == 'kdj':
                if not isinstance(result, dict) or 'k' not in result or 'd' not in result or 'j' not in result:
                    logging.warning(f"{stock_code} KDJ缓存结果格式无效，清除缓存")
                    self.cache_manager.clear_stock_cache(stock_code)
                    return None
            
            # 对于MA指标，验证结果格式
            elif indicator_type == 'ma':
                if not isinstance(result, tuple) or len(result) != 4:
                    logging.warning(f"{stock_code} MA缓存结果格式无效，清除缓存")
                    self.cache_manager.clear_stock_cache(stock_code)
                    return None
        
        return result
        
    def get_all_cached_results(self, stock_code):
        """获取某只股票的所有缓存结果（带有效性验证）"""
        results = {}
        for indicator_type in self.calculation_intervals.keys():
            result = self.get_cached_result(stock_code, indicator_type)
            if result is not None:
                results[indicator_type] = result
            else:
                # 记录缓存缺失的指标
                logging.debug(f"{stock_code} {indicator_type} 缓存结果为空")
        return results
        
    def clear_cache(self, stock_code=None):
        """清理缓存"""
        if stock_code:
            self.cache_manager.clear_stock_cache(stock_code)
        else:
            self.cache_manager.clear_all_cache()
            
    def get_queue_size(self):
        """获取队列大小"""
        return self.calculation_queue.qsize()
        
    def get_cache_stats(self):
        """获取缓存统计信息"""
        stats = self.cache_manager.get_cache_stats()
        stats['queue_size'] = self.get_queue_size()
        return stats
        
    def _cleanup_old_tasks(self, stock_code, indicator_type):
        """清理队列中的旧任务（针对同一股票和指标类型）"""
        try:
            # 创建一个临时列表存储需要保留的任务
            temp_tasks = []
            removed_count = 0
            
            # 遍历队列，移除旧的同类型任务
            while not self.calculation_queue.empty():
                try:
                    task = self.calculation_queue.get_nowait()
                    # 如果是同一股票和指标类型的旧任务，跳过
                    if (task['stock_code'] == stock_code and 
                        task['indicator_type'] == indicator_type and
                        removed_count < 2):  # 最多移除2个旧任务
                        removed_count += 1
                        continue
                    else:
                        temp_tasks.append(task)
                except queue.Empty:
                    break
            
            # 将保留的任务放回队列
            for task in temp_tasks:
                try:
                    self.calculation_queue.put_nowait(task)
                except queue.Full:
                    break
                    
            if removed_count > 0:
                logging.info(f"清理了 {removed_count} 个 {stock_code} {indicator_type} 的旧任务")
                
        except Exception as e:
            logging.error(f"清理旧任务异常: {e}")
            
    def get_queue_health(self):
        """获取队列健康状态"""
        queue_size = self.get_queue_size()
        max_size = self.calculation_queue.maxsize
        utilization = (queue_size / max_size) * 100 if max_size > 0 else 0
        
        health_status = "健康"
        if utilization > 90:
            health_status = "危险"
        elif utilization > 70:
            health_status = "警告"
        elif utilization > 50:
            health_status = "注意"
            
        return {
            "queue_size": queue_size,
            "max_size": max_size,
            "utilization": f"{utilization:.1f}%",
            "health_status": health_status,
            "thread_count": self.thread_count
        }
        
    def get_performance_stats(self):
        """获取性能统计信息"""
        cpu_stats = self.cpu_monitor.get_cpu_stats()
        queue_health = self.get_queue_health()
        cache_stats = self.get_cache_stats()
        
        return {
            "cpu_usage": {
                "current": cpu_stats["current_cpu_usage"],
                "average": cpu_stats["avg_cpu_usage"],
                "is_low": cpu_stats["is_low_cpu"],
                "is_high": cpu_stats["is_high_cpu"]
            },
            "threads": {
                "current": self.thread_count,
                "base": self.base_thread_count,
                "multiplier": cpu_stats["thread_multiplier"]
            },
            "intervals": self.calculation_intervals.copy(),
            "queue": queue_health,
            "cache": cache_stats
        }
        
    def _start_calculation_threads(self):
        """启动计算线程"""
        for i in range(self.thread_count):
            thread = threading.Thread(target=self._calculation_worker, daemon=True, name=f"CalcThread-{i+1}")
            thread.start()
            self.calculation_threads.append(thread)
            
    def _start_dynamic_adjustment_thread(self):
        """启动动态调整线程"""
        adjustment_thread = threading.Thread(target=self._dynamic_adjustment_worker, daemon=True, name="DynamicAdjustment")
        adjustment_thread.start()
        
    def _dynamic_adjustment_worker(self):
        """动态调整工作线程"""
        while self.running:
            try:
                # 根据CPU使用率调整线程数量
                optimal_thread_count = self.cpu_monitor.get_optimal_thread_count(self.base_thread_count)
                
                if optimal_thread_count != self.thread_count:
                    self._adjust_thread_count(optimal_thread_count)
                
                # 根据CPU使用率调整计算间隔
                self._adjust_calculation_intervals()
                
                time.sleep(10)  # 每10秒检查一次
                
            except Exception as e:
                logging.error(f"动态调整异常: {e}")
                time.sleep(10)
                
    def _adjust_thread_count(self, new_thread_count):
        """调整线程数量"""
        if new_thread_count > self.thread_count:
            # 增加线程
            for i in range(self.thread_count, new_thread_count):
                thread = threading.Thread(target=self._calculation_worker, daemon=True, name=f"CalcThread-{i+1}")
                thread.start()
                self.calculation_threads.append(thread)
            logging.info(f"增加了 {new_thread_count - self.thread_count} 个计算线程")
            
        elif new_thread_count < self.thread_count:
            # 减少线程（通过标记停止，实际线程会在下次循环时自然退出）
            self.thread_count = new_thread_count
            logging.info(f"减少计算线程到 {new_thread_count} 个")
            
        self.thread_count = new_thread_count
        
    def _adjust_calculation_intervals(self):
        """根据CPU使用率调整计算间隔"""
        cpu_stats = self.cpu_monitor.get_cpu_stats()
        
        if cpu_stats["is_low_cpu"]:
            # CPU使用率低，减少计算间隔（提高频率）
            for indicator in self.calculation_intervals:
                if self.calculation_intervals[indicator] > 1:
                    self.calculation_intervals[indicator] = max(1, self.calculation_intervals[indicator] - 1)
        elif cpu_stats["is_high_cpu"]:
            # CPU使用率高，增加计算间隔（降低频率）
            for indicator in self.calculation_intervals:
                self.calculation_intervals[indicator] = min(10, self.calculation_intervals[indicator] + 1)
